#include "NumCalc.h"

#include <cmath>
#include <iostream>
#include <iomanip>

#define max(a,b) ( (a<b) ? b : a )

using std::cout;
using std::endl;

Result NumCalc::bisection(double a, double b, double precision, const Function& function, int verbosity) {
    double error;
    double xk=0;
    double xk1;
    int itCount = 0;
    if (verbosity==VERBOSITY_CSV) {
        cout << "------------------------------------------" << endl;
        cout << "iteration" << "," << "a" << "," << "b" << "," << "xk" << "," << "xk+1" << "," << "error" << endl;
    }
    do {
        ++itCount;

        xk1 = (a+b)/2.0;
        if ( (function.f(a) * function.f(xk1) ) < 0) {
            b = xk1;
        } else if ( (function.f(a) * function.f(xk1) ) > 0) {
            a = xk1;
        } else {
            //found it?
        }
        error = fabs(xk1 - xk)/ max(1,fabs(xk1));
        if (verbosity==VERBOSITY_TEXT) {
            cout << "-------------------" << endl;
            cout << "iteration " << itCount << endl;
            cout << "a = " << a << endl;
            cout << "b = " << b << endl;
            cout << "xk = " << std::setprecision(24) << std::fixed << xk << endl;
            cout << "xk+1 = " << std::setprecision(24) << std::fixed << xk1 << endl;
            cout << "error = " << std::setprecision(24) << std::fixed << error << endl;
            //cout << "" << << endl;
        } else if (verbosity==VERBOSITY_CSV) {
            cout << std::setprecision(24) << itCount << "," << a << "," << b << "," << xk << "," << xk1 << "," << error << endl;
        }
        xk = xk1;
    } while (error > precision);
    if (verbosity==VERBOSITY_TEXT || verbosity==VERBOSITY_CSV)
        cout << "========================================" << endl;
    Result r;

    r.x = xk;
    r.error = error;
    r.iterationCount = itCount;

    //this variable is set here for debug
    r.fx = function.f(xk);
    r.check = (fabs(r.fx) < precision);

    return r;
}

Result NumCalc::fixedPoint(double initial, double precision, const Function& function, const Function& fi, int verbosity) {
    double error;
    double xk=initial;
    double xk1;
    int itCount = 0;
    if (verbosity==VERBOSITY_CSV) {
        cout << "------------------------------------------" << endl;
        cout << "iteration" << "," << "xk" << "," << "xk+1" << "," << "error" << endl;
    }
    do {
        ++itCount;

        xk1 = fi.f(xk);

        error = fabs(xk1 - xk)/max(1,fabs(xk1));
        if (verbosity==VERBOSITY_TEXT) {
            cout << "-------------------" << endl;
            cout << "iteration " << itCount << endl;
            cout << "xk = " << std::setprecision(24) << std::fixed << xk << endl;
            cout << "xk+1 = " << std::setprecision(24) << std::fixed << xk1 << endl;
            cout << "error = " << std::setprecision(24) << std::fixed << error << endl;
            //cout << "" << << endl;
        } else if (verbosity==VERBOSITY_CSV) {
            cout << std::setprecision(24) << itCount << "," << xk << "," << xk1 << "," << error << endl;
        }
        xk = xk1;
    } while (error > precision);
    if (verbosity==VERBOSITY_TEXT || verbosity==VERBOSITY_CSV)
        cout << "========================================" << endl;
    Result r;

    r.x = xk;
    r.error = error;
    r.iterationCount = itCount;

    //this variable is set here for debug
    r.fx = function.f(xk);
    r.check = (fabs(r.fx) < precision);

    return r;
}

Result NumCalc::binewton(double a, double b, double precision, const Function& function, const Function& fi, int verbosity) {
    double error;
    double xk=0;
    double xk1;
    int itCount = 0;
    if (verbosity==VERBOSITY_CSV) {
        cout << "------------------------------------------" << endl;
        cout << "iteration" << "," << "xk" << "," << "xk+1" << "," << "error" << endl;
    }
    do {
        ++itCount;

        xk1 = (a+b)/2.0;
        if ( (function.f(a) * function.f(xk1) ) < 0) {
            b = xk1;
        } else if ( (function.f(a) * function.f(xk1) ) > 0) {
            a = xk1;
        } else {
            //found it
        }
        error = fabs(xk1 - xk)/max(1,fabs(xk1));
        if (verbosity==VERBOSITY_TEXT) {
            cout << "-------------------" << endl;
            cout << "iteration " << itCount << endl;
            cout << "xk = " << std::setprecision(24) << std::fixed << xk << endl;
            cout << "xk+1 = " << std::setprecision(24) << std::fixed << xk1 << endl;
            cout << "error = " << std::setprecision(24) << std::fixed << error << endl;
            //cout << "" << << endl;
        } else if (verbosity==VERBOSITY_CSV) {
            cout << std::setprecision(24) << itCount << "," << xk << "," << xk1 << "," << error << endl;
        }
        xk = xk1;
    } while ((b-a) > 1);
    do {
        ++itCount;

        xk1 = fi.f(xk);

        error = fabs(xk1 - xk)/max(1,fabs(xk1));
        if (verbosity==VERBOSITY_TEXT) {
            cout << "-------------------" << endl;
            cout << "iteration " << itCount << endl;
            cout << "xk = " << std::setprecision(24) << std::fixed << xk << endl;
            cout << "xk+1 = " << std::setprecision(24) << std::fixed << xk1 << endl;
            cout << "error = " << std::setprecision(24) << std::fixed << error << endl;
            //cout << "" << << endl;
        } else if (verbosity==VERBOSITY_CSV) {
            cout << std::setprecision(24) << itCount << "," << xk << "," << xk1 << "," << error << endl;
        }
        xk = xk1;
    } while (error > precision);
    if (verbosity==VERBOSITY_TEXT || verbosity==VERBOSITY_CSV)
        cout << "========================================" << endl;
    Result r;

    r.x = xk;
    r.error = error;
    r.iterationCount = itCount;

    //this variable is set here for debug
    r.fx = function.f(xk);
    r.check = (fabs(r.fx) < precision);
    return r;
}
